package com.mxx.common.netty;


import com.mxx.common.netty.http.NettyHttpHandler;
import com.mxx.common.netty.ws.NettyWebsocketConnectionForwardHandler;
import com.mxx.common.netty.ws.NettyWebsocketHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.NonNull;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;

/**
 * @Auther: Mr. Zeng
 * @Date: 2020/6/29 11:01
 * @Description: 暂无描述
 */
@Slf4j
public class NettyWebsocketServer implements ApplicationListener<ApplicationStartedEvent>, ApplicationContextAware {


    private NettyWebsocketHandler nettyWebSocketHandler;

    private NettyWebsocketConnectionForwardHandler connectionHttpHandler;

    private NettyHttpHandler nettyHttpHandler;

    private NettyServiceProperties nettyServiceProperties;


    @SneakyThrows
    @Override
    public void onApplicationEvent(@NonNull ApplicationStartedEvent event) {
        ServerBootstrap bootstrap = new ServerBootstrap();
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        bootstrap.group(bossGroup, workerGroup);
        bootstrap.channel(NioServerSocketChannel.class);
        bootstrap.childOption(NioChannelOption.TCP_NODELAY, nettyServiceProperties.getNoDelay());
        bootstrap.childOption(NioChannelOption.SO_REUSEADDR, nettyServiceProperties.getReuseAddr());
        bootstrap.childOption(NioChannelOption.SO_KEEPALIVE, nettyServiceProperties.getKeepAlive());
        bootstrap.childOption(NioChannelOption.SO_RCVBUF, nettyServiceProperties.getRcvBuf());
        bootstrap.childOption(NioChannelOption.SO_SNDBUF, nettyServiceProperties.getSendBuf());
        bootstrap.childHandler(new NettyWebsocketChannelInitializer(nettyWebSocketHandler, connectionHttpHandler, nettyHttpHandler, nettyServiceProperties));
        ChannelFuture channelFuture = bootstrap.bind(nettyServiceProperties.getPort()).sync().addListener(future -> {
            String logBanner = "\n\n" +
                    "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n" +
                    "*                                                                                   *\n" +
                    "*                                                                                   *\n" +
                    "*                   Netty Websocket Server started on port {}.                    *\n" +
                    "*                                                                                   *\n" +
                    "*                                                                                   *\n" +
                    "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n";
            log.info(logBanner, nettyServiceProperties.getPort());

            log.info("Netty WebSocket Server Start  ............");
        });
        channelFuture.channel().closeFuture().addListener(future -> {
            log.info("Netty WebSocket Server Start Shutdown ............");
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        });
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        nettyWebSocketHandler = applicationContext.getBean(NettyWebsocketHandler.class);
        connectionHttpHandler = applicationContext.getBean(NettyWebsocketConnectionForwardHandler.class);
        nettyHttpHandler = applicationContext.getBean(NettyHttpHandler.class);
        nettyServiceProperties = applicationContext.getBean(NettyServiceProperties.class);

    }


}
